<script lang="ts">
    import { onDestroy, onMount, untrack } from "svelte";
    import { useClassList } from "../utils/useClassList";
    import type { TagConfig, TagGroupProps } from "./TagGroup";
    import { Tag } from "../Tag";
    import { Popover } from "../Popover";
    import { createUniqueId } from "../utils/createUniqueId";
    import { useFormItemContext } from "../FormItem/FormItem.svelte";

    let { multi = true, gutter = 2, value = $bindable(multi ? [] : undefined), ...props }: TagGroupProps = $props();
    const ctx = useFormItemContext();

    const classList = $derived(
        useClassList(props, "cm-tag-group", {
            "cm-tag-group-overflow": props.max === "auto",
            "cm-tag-group-checkable": props.checkable,
        })
    );

    const tooltipTheme = props.tooltipTheme ?? "light";
    const tooltipAlign = props.tooltipAlign ?? "top";
    const tooltipTrigger = props.tooltipTrigger ?? "hover";

    let wrap: any;
    const showStyle = "position: ; height: ; point-event: ; overflow: ;";

    const hideStyle = "position: absolute; height: 0px; point-event: none; overflow: hidden;";

    const store = $state({
        list: [],
        show: [],
        hide: [],
    } as { list: TagConfig[]; show: TagConfig[]; hide: TagConfig[] });

    const onClose = (item: TagConfig, e: any) => {
        const newList = store.list.filter((aitem) => {
            return aitem.id !== item.id;
        });
        store.list = newList;
        props.onclose?.(item, e);
        queueMicrotask(() => {
            onSizeChange();
        });
    };

    $effect(() => {
        const arr = props.data.map((item: any) => {
            if (item.id === undefined) {
                item.id = createUniqueId();
            }
            if (props.max === "auto") {
                item._style = hideStyle;
            }
            return item;
        });
        store.list = arr;
    });

    $effect(() => {
        const list = store.list;
        const show: TagConfig[] = [];
        const hide: TagConfig[] = [];
        if (props.max === "auto") {
            store.hide = hide;
            queueMicrotask(() => {
                onSizeChange();
            });
        } else {
            const max = props.max ?? list.length;
            untrack(() => {
                for (let i = 0; i < max; i++) {
                    list[i] && show.push(list[i]);
                }
                const length = list.length;
                for (let j = max; j < length; j++) {
                    hide.push(list[j]);
                }
                store.show = show;
                store.hide = hide;
            });
        }
    });

    // 隐藏
    const hideTag = (index: number) => {
        if (!store.hide.includes(store.list[index])) {
            store.hide.push(store.list[index]);
        }
        store.list[index]._style = hideStyle;
    };

    // 显示
    const showTag = (index: number) => {
        // 已经隐藏的从hide中移除
        const idx = store.hide.indexOf(store.list[index]);
        if (idx > -1) {
            store.hide.splice(idx, 1);
        }
        store.list[index]._style = showStyle;
    };

    const onSizeChange = () => {
        if (props.max !== "auto") {
            return;
        }
        const wrapRect = wrap.getBoundingClientRect();

        const tags: any[] = wrap.querySelectorAll(".cm-tag:not(.cm-tag-more)");
        let w = 0;

        const more = wrap.querySelector(".cm-tag-more");
        const shows: number[] = [];
        const hides: number[] = [];
        tags.forEach((tag, index) => {
            const moreRect = more?.getBoundingClientRect();
            const moreWidth = moreRect ? 5 + moreRect?.width : 25;
            const tagWidth = tag.offsetWidth;
            if (w + (index === 0 ? 0 : 5) + tagWidth < wrapRect.width) {
                if (index < store.list.length - 1 && w + (index === 0 ? 0 : 5) + tagWidth + moreWidth > wrapRect.width) {
                    w = w + (index === 0 ? 0 : 5) + tagWidth;
                    hides.push(index);
                } else {
                    w = w + (index === 0 ? 0 : 5) + tagWidth;
                    if (tag.style.height === "0px") {
                        shows.push(index);
                    }
                }
            } else {
                hides.push(index);
            }
        });
        // 批量修改
        shows.forEach((index) => {
            showTag(index);
        });
        hides.forEach((index) => {
            hideTag(index);
        });
    };

    onMount(() => {
        const ob = new ResizeObserver(() => {
            onSizeChange();
        });
        if (props.max === "auto") {
            ob.observe(wrap);
        }

        onDestroy(() => {
            ob.disconnect();
        });
    });

    const onClick = (item: TagConfig) => {
        if (props.checkable) {
            let val = value || [];
            if (multi && Array.isArray(val)) {
                if (val?.includes(item.id)) {
                    val = val.filter((a) => a !== item.id);
                } else {
                    val?.push(item.id);
                }
            } else {
                val = item.id;
            }
            value = val;
            props.onchange?.($state.snapshot(value));
            ctx?.onFieldChange?.();
        }
    };

    const isChecked = (item: TagConfig) => {
        if (multi && Array.isArray(value)) {
            return value?.includes(item.id);
        } else {
            return value === item.id;
        }
    };
</script>

<div class={classList} style={props.style} style:--cui-taggroup-gutter={gutter + "px"} bind:this={wrap}>
    {#if props.max === "auto"}
        {#each store.list as item (item.id)}
            <Tag
                closable={props.closable}
                style={item._style}
                class={item.class}
                border={props.border}
                size={props.size}
                theme={item.theme}
                avatar={item.avatar}
                checked={isChecked(item)}
                onclick={() => onClick(item)}
                onclose={(e: any) => {
                    onClose(item, e);
                }}>{item.title}</Tag
            >
        {/each}
    {:else}
        {#each store.show as item (item.id)}
            <Tag
                closable={props.closable}
                size={props.size}
                class={item.class}
                border={props.border}
                theme={item.theme}
                avatar={item.avatar}
                checked={isChecked(item)}
                onclick={() => onClick(item)}
                onclose={(e: any) => {
                    onClose(item, e);
                }}>{item.title}</Tag
            >
        {/each}
    {/if}
    {#if store.hide.length}
        {#if props.showMore}
            <Popover class="cm-tag-group-more-popover" align={tooltipAlign} arrow theme={tooltipTheme} trigger={tooltipTrigger} style={props.tooltipStyle}>
                {#snippet content()}
                    <div class="cm-tag-group-more-wrap">
                        {#each store.hide as item (item.id)}
                            <Tag
                                size={props.size}
                                theme={item.theme}
                                class={item.class}
                                border={props.border}
                                closable={props.moreCloseable}
                                onclose={(e: any) => {
                                    onClose(item, e);
                                }}
                                avatar={item.avatar}>{item.title}</Tag
                            >
                        {/each}
                    </div>
                {/snippet}
                <Tag class="cm-tag-more"><span>+</span>{store.hide.length}</Tag>
            </Popover>
        {:else}
            <Tag class="cm-tag-more"><span>+</span>{store.hide.length}</Tag>
        {/if}
    {/if}
    {@render props.extra?.()}
</div>
